/* 
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

***********

This C++ CGI script is used to validate input controls for Touchscreen by a
validation Perl Compatible regular expression, available letters, and the value typed so far.
This script outputs a string of valid characters from the list of available keys.


requires pcre and pcre_dev

Compile thuswise:
  gcc -Wall -o validate.cgi validate.cpp -lpcre

 */

#include <cstdio>
#include <cstdlib>
#include <string>
#include <iostream>
#include <pcre.h>

#define OVECCOUNT 30    /* should be a multiple of 3 */

using namespace std;

int main(int argc, char **argv)
{
  pcre *re;
  const char *error;
  string pattern ="";
  string subject = "";
  int erroffset;
  int ovector[OVECCOUNT];
  int subject_length;
  int rc;

  string data;
  char str1[BUFSIZ];
  char str2[BUFSIZ];
  char keys[BUFSIZ];

  printf("%s%c%c\n", "Content-Type:text/html;charset=iso-8859-1",13,10);

  /**************************************************************************
  * First, sort out the command line. There is only one possible option at  *
  * the moment, "-g" to request repeated matching to find all occurrences,  *
  * like Perl's /g option. We set the variable find_all to a non-zero value *
  * if the -g option is present. Apart from that, there must be exactly two *
  * arguments.                                                              *
  **************************************************************************/

  data = getenv("QUERY_STRING");
  //data = "p=(jan|jun|jul)&s=i&keys=abcdeiou";
  if(data != "") {
    //sscanf(data.c_str(),"p=%[^&]&s=%[^&]*&keys=%s",str1,str2,keys);
    sscanf(data.c_str(),"p=%[^&]&keys=%[^&]&s=%s",str1,keys,str2);
  }

  pattern = str1;
  subject = str2;
  subject_length = (int)strlen(subject.c_str());

  //printf("Pattern: %s<br/>\n", pattern.c_str());
  //printf("Subject: %s<br/>\n", subject.c_str());
  //printf("Keys   : %s<br/>\n", keys);

    
  /*************************************************************************
  * Now we are going to compile the regular expression pattern, and handle *
  * and errors that are detected.                                          *
  *************************************************************************/

  re = pcre_compile(
    pattern.c_str(),              /* the pattern */
    PCRE_CASELESS,                    /* default options */
    &error,               /* for error message */
    &erroffset,           /* for error offset */
    NULL);                /* use default character tables */

  /* Compilation failed: print the error message and exit */

  if (re == NULL)
    {
    //printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
    printf("false");
    return 1;
    }


  /*************************************************************************
  * If the compilation succeeded, we call PCRE again, in order to do a     *
  * pattern match against the subject string. This does just ONE match. If *
  * further matching is needed, it will be done below.                     *
  *************************************************************************/
  string nextSubject = "";
  string validChars = "";
  int i = 0;
  /* 
  rc = pcre_exec(re, NULL, subject.c_str(), subject_length,0,
                 PCRE_PARTIAL,ovector,OVECCOUNT);
  if (rc < 0) {
    switch(rc) {
      case PCRE_ERROR_NOMATCH: printf("false,"); break;
      case PCRE_ERROR_PARTIAL: printf("true,");  break;
      default: printf("false,"); break;
    }
  } else {
    printf("true,");
  }
  */
  //printf("# of chars: %d\n", (int)strlen(keys));
  for (i=0;i<(int)strlen(keys); i++) {
    nextSubject = subject + keys[i];
    
    rc = pcre_exec(
      re,                   /* the compiled pattern */
      NULL,                 /* no extra data - we didn't study the pattern */
      nextSubject.c_str(),          /* the subject string */
      subject_length+1,     /* the length of the subject */
      0,                    /* start at offset 0 in the subject */
      PCRE_PARTIAL,         /* default options */
      ovector,              /* output vector for substring information */
      OVECCOUNT);           /* number of elements in the output vector */

    /* Matching failed: handle error cases */


    if (rc < 0) {
      switch(rc) {
        //case PCRE_ERROR_NOMATCH: printf("No match\n"); break;
        case PCRE_ERROR_NOMATCH: /*printf("false,");*/ break;
        //case PCRE_ERROR_PARTIAL: printf("Partial match\n"); break;
        case PCRE_ERROR_PARTIAL: /*cout << keys[i]<< ";";*/
                                 validChars += keys[i];
                                 break;
        /*
        Handle other special cases if you like
        */
        //default: printf("Matching error %d\n", rc); break;
        default: /*printf("false,");*/ break;
      }
      //return 1;
    } else {
      /* Match succeded */
      /*printf("\nMatch succeeded at offset %d\n", ovector[0]); */
      //printf("true");
      validChars += keys[i];
    }
  }

  cout << validChars;
  free(re);     /* Release memory used for the compiled pattern */

  return 0;
}

/* End of pcredemo.c */
